/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package plash.geom;

import java.util.ArrayList;

/**
 *
 * @author  #0K Srinivasan <hashok.com>
 */
public class Rectangle
{

    private int _x;
    private int _y;
    private int _width;
    private int _height;

    public static Rectangle minSize(Rectangle rectangle1, Rectangle rectangle2)
    {
        return (rectangle1.getArea() < rectangle2.getArea()) ? rectangle1 : rectangle2;
    }

    public static Rectangle maxSize(Rectangle rectangle1, Rectangle rectangle2)
    {
        return (rectangle1.getArea() > rectangle2.getArea()) ? rectangle1 : rectangle2;
    }

    public Rectangle()
    {
        this(0, 0, 0, 0);
    }

    public Rectangle(int x, int y, int width, int height)
    {
        _x = x;
        _y = y;
        _width = width;
        _height = height;
    }

    public Rectangle(Point location, Point dimensions)
    {
        this(location.getX(), location.getY(), dimensions.getX(), dimensions.getY());
    }

    public Rectangle(Point location, int width, int height)
    {
        this(location.getX(), location.getY(), width, height);
    }

    public Rectangle(int x, int y, Point dimensions)
    {
        this(x, y, dimensions.getX(), dimensions.getY());
    }

    public int getArea()
    {
        return this.getWidth() * this.getHeight();
    }

    public int getX()
    {
        return _x;
    }

    public void setX(int _x)
    {
        this._x = _x;
    }

    public int getY()
    {
        return _y;
    }

    public void setY(int _y)
    {
        this._y = _y;
    }

    public int getWidth()
    {
        return _width;
    }

    public void setWidth(int _width)
    {
        this._width = _width;
    }

    public int getHeight()
    {
        return _height;
    }

    public void setHeight(int _height)
    {
        this._height = _height;
    }

    public int getTop()
    {
        return this.getY();
    }

    public int getBottom()
    {
        return this.getY() + this.getHeight();
    }

    public int getLeft()
    {
        return this.getX();
    }

    public int getRight()
    {
        return this.getX() + this.getWidth();
    }

    public Point getTopLeft()
    {
        return new Point(this.getLeft(), this.getTop());
    }

    public Point getTopRight()
    {
        return new Point(this.getRight(), this.getTop());
    }

    public Point getBottomLeft()
    {
        return new Point(this.getLeft(), this.getBottom());
    }

    public Point getBottomRight()
    {
        return new Point(this.getRight(), this.getBottom());
    }

    public boolean isEmpty()
    {
        return ((this.getWidth() == 0) || (this.getHeight() == 0));
    }

    public boolean equals(Rectangle toCheck)
    {
        return ((this.getX() == toCheck.getX()) && (this.getY() == toCheck.getY()) && (this.getWidth() == toCheck.getWidth() && (this.getHeight() == toCheck.getHeight())));
    }

    public boolean containsPoint(int x, int y)
    {
        boolean insideHorizontal = (x > this.getLeft()) && (x < this.getRight());
        boolean insideVertical = (y > this.getTop()) && (y < this.getBottom());
        
        return (insideHorizontal && insideVertical);
    }

    public boolean containsPoint(Point point)
    {
        return this.containsPoint(point.getX(), point.getY());
    }

    public boolean containsRectangle(int x, int y, int width, int height)
    {
        return this.containsRectangle(new Rectangle(x, y, width, height));
    }

    public boolean containsRectangle(Rectangle toCheck)
    {
        if (this.equals(toCheck))
        {
            return false;
        }
        boolean isLeftOutside = toCheck.getLeft() > this.getLeft();
        boolean isRightInside = toCheck.getRight() < this.getRight();

        boolean isTopOutside = toCheck.getTop() > this.getTop();
        boolean isBottomInside = toCheck.getBottom() < this.getBottom();

        return isLeftOutside && isRightInside && isTopOutside && isBottomInside;
    }

    public boolean intersects(int x, int y, int width, int height)
    {
        return this.intersects(new Rectangle(x, y, width, height));
    }

    public boolean intersects(Rectangle toIntersect)
    {
        int sumWidth;
        int sumHeight;

        Rectangle union;

        if (toIntersect.isEmpty() || this.isEmpty())
        {
            return false;
        }

        if (this.containsRectangle(toIntersect) || toIntersect.containsRectangle(this))
        {
            return false;
        }

        if (this.equals(toIntersect))
        {
            return false;
        }

        union = this.union(toIntersect);
        sumWidth = this.getWidth() + toIntersect.getWidth();
        sumHeight = this.getHeight() + toIntersect.getHeight();
        
        return ((sumWidth > union.getWidth()) && (sumHeight > union.getHeight()));
    }

    public Rectangle intersection(int x, int y, int width, int height)
    {
        return this.intersection(new Rectangle(x, y, width, height));
    }

    public Rectangle intersection(Rectangle toIntersect)
    {
        int left;
        int right;

        int top;
        int bottom;

        int width;
        int height;

        if (!this.intersects(toIntersect))
        {
            return new Rectangle(0, 0, 0, 0);
        }
        else
        {
            left = java.lang.Math.max(this.getLeft(), toIntersect.getLeft());
            right = java.lang.Math.min(this.getRight(), toIntersect.getRight());

            top = java.lang.Math.max(this.getTop(), toIntersect.getTop());
            bottom = java.lang.Math.min(this.getBottom(), toIntersect.getBottom());

            width = right - left;
            height = bottom - top;

            return new Rectangle(left, top, width, height);
        }
    }

    public Rectangle union(int x, int y, int width, int height)
    {
        return this.union(new Rectangle(x, y, width, height));
    }

    public Rectangle union(Rectangle toUnion)
    {
        int left = java.lang.Math.min(this.getLeft(), toUnion.getLeft());
        int top = java.lang.Math.min(this.getTop(), toUnion.getTop());

        int right = java.lang.Math.max(this.getRight(), toUnion.getRight());
        int bottom = java.lang.Math.max(this.getBottom(), toUnion.getBottom());

        int width = right - left;
        int height = bottom - top;

        Point location = new Point(left, top);
        Point dimensions = new Point(width, height);

        return new Rectangle(location, dimensions);
    }

    public void offset(int dx, int dy)
    {
        this.setX(this.getX() + dx);
        this.setY(this.getY() + dy);
    }

    public void offset(Point point)
    {
        this.offset(point.getX(), point.getY());
    }
    
    @Override
    public Rectangle clone()
    {
        return new Rectangle(this.getX(), this.getY(), this.getWidth(), this.getHeight());
    }

    @Override
    public String toString()
    {
        return "(x=" + this.getX() + ", y=" + this.getY() + ", width=" + this.getWidth() + ", height=" + this.getHeight();
    }
}
